package br.unifor.cct.mia.evaluate;

import java.io.IOException;
import java.util.Map;
import java.util.StringTokenizer;

import weka.clusterers.ClusterEvaluation;
import weka.clusterers.Cobweb;
import br.unifor.cct.mia.dataenhancement.DatabaseUtil;
import br.unifor.cct.mia.evolutionary.CobwebGenotype;
import br.unifor.cct.mia.evolutionary.Genotype;
import br.unifor.cct.mia.ga.Ga;
import br.unifor.cct.mia.util.Methods;
import br.unifor.cct.mia.util.SaveReport;

public class WekaIOCobwebCUtilityEvaluate implements Evaluate {

	private Map genesAnt;
	private String structure;
	private String dataset;
	private String[] options;
		
	public double cost(Genotype gen) {		
		double sum = 0;
		
		Integer hashCode = new Integer(Methods.geneToString(gen.getGene()).hashCode());
		if (!genesAnt.containsKey(hashCode)) {			

			try {
				SaveReport report = new SaveReport("temp/result.txt",structure);
				
				for ( int i=0; i<gen.getGene().length-2; i++ ) {
					double value = gen.getGene(i);
					String line = DatabaseUtil.readLine(dataset,(int)value);						
					report.addLine(line);						
					
				}
				report.saveToDisk();
				
				double ac = gen.getGene( gen.getGene().length-2 );
				double co = gen.getGene( gen.getGene().length-1 );
				
				String[] cwParam = new String[4];
				cwParam[0] = "-A";
				cwParam[1] = String.valueOf(ac);
				cwParam[2] = "-C";
				cwParam[3] = String.valueOf(co);
				
				Cobweb cobweb = new Cobweb();
				cobweb.setOptions(cwParam);
								
				String[] param = new String[2];
				param[0] = "-t";
				param[1] = "temp/result.txt";
				String evaluate = ClusterEvaluation.evaluateClusterer(cobweb,param);
					
				if ( cobweb.m_cobwebTree.m_children==null
						|| cobweb.m_cobwebTree.m_children.size() == 0 ) {
					sum = 0;
				} 
				else {
					sum = cobweb.m_cobwebTree.categoryUtility();
				}				
				
				StringTokenizer tokenizer = new StringTokenizer(evaluate,"\n");
				
				int mergers = 0;
				int splits = 0;
				int clusters = 0;
				int count = 0;
				while ( tokenizer.hasMoreTokens() ) {
					String token = tokenizer.nextToken();
					if ( count == 3 ) break;
					if ( token.startsWith("Number of merges:") ) {
						String aux = token.substring( 
								token.indexOf(":")+2, token.length() );
						mergers = Integer.parseInt(aux);
						count++;
					}
					else if ( token.startsWith("Number of splits:") ) {
						String aux = token.substring( 
								token.indexOf(":")+2, token.length() );
						splits = Integer.parseInt(aux);
						count++;
					}
					else if ( token.startsWith("Number of clusters:") ) {
						String aux = token.substring( 
								token.indexOf(":")+2, token.length() );
						clusters = Integer.parseInt(aux);
						count++;
					}
				}		
				
				
				/*int cont = 0;
				ArrayList list = new ArrayList();
				list.add(cobweb.m_cobwebTree);
				while ( !list.isEmpty() ) {
					CNode node = (CNode)list.remove(0);
					cont++;
					
					FastVector filhos = node.m_children;
					if ( filhos != null ) {
						for ( int i=0; i<filhos.size(); i++ ) {
							list.add(filhos.elementAt(i));
						}						
					}
				}
				System.out.println("Cont: "+cont);*/
				
				((CobwebGenotype)gen).setNumCluster(clusters);
				((CobwebGenotype)gen).setNumSplit(splits);
				((CobwebGenotype)gen).setNumMerge(mergers);		
				
				//System.out.println(gen.toString());
				
				//System.out.println("SUM "+sum);
			} catch (IOException e1) {
				e1.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}			
			
			genesAnt.put(hashCode, new Double(sum));
		}
		else {
			sum = ((Double)genesAnt.get(hashCode)).doubleValue();
		}
		
		return sum;
	}

	public Object evaluate(Object value,String[] options) {
		this.options = options;		
		Object[] o = (Object[]) value;
		structure = (String) o[0];
		genesAnt = (Map) o[1];
		dataset = (String) o[2];	
		Ga Ga = (Ga)o[3];
		
		Ga.sum = 0;
		Ga.indexBestWorst[0] = Ga.indexBestWorst[1] = 0;
       
        for(int i = 0; i < Ga.configurations.getPopsize(); i++) {        	
        	Ga.population[i].setFitness(cost((Genotype)Ga.population[i]));                    	
            if (Ga.population[i].getFitness() > Ga.population[Ga.indexBestWorst[0]].getFitness()) 
            	Ga.indexBestWorst[0] = i;
            else 
            	if (Ga.population[i].getFitness() < Ga.population[Ga.indexBestWorst[1]].getFitness()) 
            		Ga.indexBestWorst[1] = i;
            	
            Ga.sum += Ga.population[i].getFitness();
        }
        
		return Ga.population;
	}
}
